{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1e112198",
   "metadata": {},
   "source": [
    "### Flow Matching U-Net with Time Embeddings\n",
    "\n",
    "This is an implementation of a U-Net architecture conditioned on time embeddings for flow matching tasks. The model takes in noisy data and predicts the vector field at a given time step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "22bfe034",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "import os\n",
    "\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision import datasets, transforms, utils"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd91fc93",
   "metadata": {},
   "source": [
    "### Sinusoidal Time Embeddings and U-Net Model\n",
    "\n",
    "We implement sinusoidal time embeddings and a U-Net architecture that incorporates these embeddings to condition the model on time.\n",
    "\n",
    "Note that the model input is noise and the time embedding, and the output is the predicted vector field at that time step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "62cbd176",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ----------------------------\n",
    "# Utilities: time embedding\n",
    "# ----------------------------\n",
    "class SinusoidalPosEmb(nn.Module):\n",
    "    def __init__(self, dim):\n",
    "        super().__init__()\n",
    "        self.dim = dim\n",
    "\n",
    "    def forward(self, t):  # t shape: (B,)\n",
    "        device = t.device\n",
    "        half = self.dim // 2\n",
    "        emb = torch.exp(torch.arange(half, device=device) * -(math.log(10000) / (half - 1)))\n",
    "        emb = t[:, None] * emb[None, :]  # (B, half)\n",
    "        emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=-1)\n",
    "        if self.dim % 2 == 1:  # odd dim\n",
    "            emb = F.pad(emb, (0, 1))\n",
    "        return emb  # (B, dim)\n",
    "\n",
    "# ----------------------------\n",
    "# Small U-Net for 1x28x28 images\n",
    "# ----------------------------\n",
    "def conv_block(in_c, out_c, time_emb_dim=None):\n",
    "    layers = [\n",
    "        nn.Conv2d(in_c, out_c, kernel_size=3, padding=1),\n",
    "        nn.GroupNorm(8, out_c),\n",
    "        nn.SiLU(),\n",
    "    ]\n",
    "    if time_emb_dim is not None:\n",
    "        # add time-conditioned bias after conv\n",
    "        layers.append(TimeCondition(out_c, time_emb_dim))\n",
    "    return nn.Sequential(*layers)\n",
    "\n",
    "class TimeCondition(nn.Module):\n",
    "    def __init__(self, channels, time_emb_dim):\n",
    "        super().__init__()\n",
    "        self.proj = nn.Linear(time_emb_dim, channels)\n",
    "\n",
    "    def forward(self, x):\n",
    "        # this module will never be used stand-alone in my conv_block chain\n",
    "        raise NotImplementedError(\"TimeCondition is used in UNet forward directly.\")\n",
    "\n",
    "class UNetSimple(nn.Module):\n",
    "    def __init__(self, time_emb_dim=128):\n",
    "        super().__init__()\n",
    "        self.time_emb = SinusoidalPosEmb(time_emb_dim)\n",
    "        self.time_mlp = nn.Sequential(\n",
    "            nn.Linear(time_emb_dim, time_emb_dim * 2),\n",
    "            nn.SiLU(),\n",
    "            nn.Linear(time_emb_dim * 2, time_emb_dim),\n",
    "        )\n",
    "\n",
    "        # Encoder\n",
    "        self.inc = nn.Sequential(\n",
    "            nn.Conv2d(1, 32, kernel_size=3, padding=1),\n",
    "            nn.GroupNorm(8, 32),\n",
    "            nn.SiLU(),\n",
    "        )\n",
    "        self.down1 = nn.Sequential(\n",
    "            nn.Conv2d(32, 64, kernel_size=4, stride=2, padding=1),  # 28->14\n",
    "            nn.GroupNorm(8, 64),\n",
    "            nn.SiLU(),\n",
    "        )\n",
    "        self.down2 = nn.Sequential(\n",
    "            nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1),  # 14->7\n",
    "            nn.GroupNorm(8, 128),\n",
    "            nn.SiLU(),\n",
    "        )\n",
    "\n",
    "        # Bottleneck\n",
    "        self.mid = nn.Sequential(\n",
    "            nn.Conv2d(128, 128, 3, padding=1),\n",
    "            nn.GroupNorm(8, 128),\n",
    "            nn.SiLU(),\n",
    "            nn.Conv2d(128, 128, 3, padding=1),\n",
    "            nn.GroupNorm(8, 128),\n",
    "            nn.SiLU(),\n",
    "        )\n",
    "\n",
    "        # Decoder\n",
    "        self.up2 = nn.Sequential(\n",
    "            nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1),  # 7->14\n",
    "            nn.GroupNorm(8, 64),\n",
    "            nn.SiLU(),\n",
    "        )\n",
    "        self.up1 = nn.Sequential(\n",
    "            nn.ConvTranspose2d(128, 32, kernel_size=4, stride=2, padding=1),  # 14->28\n",
    "            nn.GroupNorm(8, 32),\n",
    "            nn.SiLU(),\n",
    "        )\n",
    "\n",
    "        self.outc = nn.Sequential(\n",
    "            nn.Conv2d(64, 32, kernel_size=3, padding=1),\n",
    "            nn.GroupNorm(8, 32),\n",
    "            nn.SiLU(),\n",
    "            nn.Conv2d(32, 1, kernel_size=3, padding=1),\n",
    "        )\n",
    "\n",
    "        # small MLP to inject time into features at each stage\n",
    "        self.time_proj0 = nn.Linear(time_emb_dim, 32)\n",
    "        self.time_proj1 = nn.Linear(time_emb_dim, 64)\n",
    "        self.time_proj2 = nn.Linear(time_emb_dim, 128)\n",
    "        self.time_proj_mid = nn.Linear(time_emb_dim, 128)\n",
    "        self.time_proj_up1 = nn.Linear(time_emb_dim, 128)\n",
    "        self.time_proj_up2 = nn.Linear(time_emb_dim, 64)\n",
    "\n",
    "    def forward(self, x, t):\n",
    "        \"\"\"\n",
    "        x: (B, 1, 28, 28)\n",
    "        t: (B,) in [0,1]\n",
    "        output: predicted velocity v(x_t, t) same shape as x\n",
    "        \"\"\"\n",
    "        B = x.shape[0]\n",
    "        te = self.time_emb(t)         # (B, time_dim)\n",
    "        te = self.time_mlp(te)        # (B, time_dim)\n",
    "\n",
    "        # encode\n",
    "        e0 = self.inc(x)              # (B,32,28,28)\n",
    "        e0 = e0 + self.time_proj0(te)[:, :, None, None]\n",
    "        e1 = self.down1(e0)           # (B,64,14,14)\n",
    "        e1 = e1 + self.time_proj1(te)[:, :, None, None]\n",
    "        e2 = self.down2(e1)           # (B,128,7,7)\n",
    "        e2 = e2 + self.time_proj2(te)[:, :, None, None]\n",
    "\n",
    "        # mid\n",
    "        m = self.mid(e2)\n",
    "        m = m + self.time_proj_mid(te)[:, :, None, None]\n",
    "        # decode\n",
    "        d2 = self.up2(m)              # (B,64,14,14)\n",
    "        d2 = torch.cat([d2, e1], dim=1)  # (B,128,14,14)\n",
    "\n",
    "        d2 = d2 + self.time_proj_up1(te)[:, :, None, None]\n",
    "\n",
    "        d1 = self.up1(d2)             # (B,32,28,28)\n",
    "        d1 = torch.cat([d1, e0], dim=1)  # (B,64,28,28)\n",
    "        d1 = d1 + self.time_proj_up2(te)[:, :, None, None]\n",
    "\n",
    "        out = self.outc(d1)           # (B,1,28,28)  => velocity\n",
    "        return out\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "06637c55",
   "metadata": {},
   "source": [
    "### Sampler for Flow Matching using Optimal Transport\n",
    "\n",
    "The noise sampler generates samples from the learned flow matching model using optimal transport principles. The equation used is based on the flow matching framework.\n",
    "\n",
    "$$ x_t = (1-t) \\epsilon + t z $$\n",
    "\n",
    "The model is trained to predict the vector field that transports the noise $\\epsilon$ to the data $z$ over time $t$. The model equation is given by:\n",
    "\n",
    "$$ v_\\theta(x_t, t) \\approx \\frac{d}{dt} x_t = z - \\epsilon $$\n",
    "\n",
    "The ground truth vector field is computed as:\n",
    "\n",
    "$$ u_gt = z - \\epsilon $$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "a1416644",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ----------------------------\n",
    "# Flow matching specifics\n",
    "# For linear interpolation x_t = (1 - t) * eps + t * z\n",
    "# => dx_t/dt = z - eps  (simple constant velocity)\n",
    "# We train network u_theta(x_t, t) to match z - eps (MSE)\n",
    "# ----------------------------\n",
    "\n",
    "def sample_xt(z, eps, t):\n",
    "    # z, eps: (B, C, H, W) ; t: (B,) scalar in [0,1]\n",
    "    # simple linear interpolation\n",
    "    t = t.view(-1, 1, 1, 1)\n",
    "    return (1 - t) * eps + t * z\n",
    "\n",
    "def train_flowmatch(\n",
    "    device='cuda' if torch.cuda.is_available() else 'cpu',\n",
    "    epochs=10,\n",
    "    batch_size=128,\n",
    "    lr=2e-4,\n",
    "    steps_per_epoch=None,\n",
    "    model_save_dir='models',\n",
    "    sample_dir='samples',\n",
    "    integration_steps=100,\n",
    "):\n",
    "    os.makedirs(model_save_dir, exist_ok=True)\n",
    "    os.makedirs(sample_dir, exist_ok=True)\n",
    "\n",
    "    transform = transforms.Compose([\n",
    "        transforms.ToTensor(),             # [0,1]\n",
    "        transforms.Normalize((0.5,), (0.5,))  # -> [-1,1]\n",
    "    ])\n",
    "    dataset = datasets.MNIST(root='~/data', download=True, train=True, transform=transform)\n",
    "    loader = DataLoader(dataset, batch_size=batch_size, shuffle=True, num_workers=2, pin_memory=True)\n",
    "\n",
    "    model = UNetSimple(time_emb_dim=128).to(device)\n",
    "    opt = torch.optim.Adam(model.parameters(), lr=lr)\n",
    "    mse = nn.MSELoss()\n",
    "\n",
    "    if steps_per_epoch is None:\n",
    "        steps_per_epoch = len(loader)\n",
    "\n",
    "    for ep in range(1, epochs + 1):\n",
    "        model.train()\n",
    "        running_loss = 0.0\n",
    "        for step, (z, _) in enumerate(loader, start=1):\n",
    "            z = z.to(device)  # (B,1,28,28)\n",
    "            B = z.shape[0]\n",
    "\n",
    "            # sample noise eps ~ N(0, I) with same shape as z\n",
    "            eps = torch.randn_like(z).to(device)\n",
    "\n",
    "            # sample t ~ Uniform(0,1)\n",
    "            t = torch.rand(B, device=device)\n",
    "\n",
    "            # compute xt and target velocity u_gt = z - eps\n",
    "            xt = sample_xt(z, eps, t)  # (B,1,28,28)\n",
    "            u_gt = z - eps           # (B,1,28,28)  (independent of t for linear interp)\n",
    "\n",
    "            # model predicts u_theta(xt, t)\n",
    "            u_pred = model(xt, t)\n",
    "\n",
    "            loss = mse(u_pred, u_gt)\n",
    "\n",
    "            opt.zero_grad()\n",
    "            loss.backward()\n",
    "            opt.step()\n",
    "\n",
    "            running_loss += loss.item()\n",
    "\n",
    "            if step % 200 == 0 or step == steps_per_epoch:\n",
    "                avg = running_loss / step\n",
    "                print(f\"Epoch {ep} Step {step}/{steps_per_epoch} Loss: {avg:.6f}\")\n",
    "\n",
    "            # limit to steps_per_epoch if specified smaller than dataset length\n",
    "            if step >= steps_per_epoch:\n",
    "                break\n",
    "\n",
    "        # end epoch\n",
    "        avg_epoch_loss = running_loss / steps_per_epoch\n",
    "        print(f\"=== Epoch {ep} completed. Avg loss: {avg_epoch_loss:.6f} ===\")\n",
    "\n",
    "        # save checkpoint\n",
    "        torch.save(model.state_dict(), os.path.join(model_save_dir, f'unet_flowmatch_ep{ep}.pt'))\n",
    "\n",
    "        # sample from the model by integrating dx/dt = v_theta(x, t) from t=0..1\n",
    "        sample_and_save(model, device, sample_dir, epoch=ep, n_samples=16, steps=integration_steps)\n",
    "\n",
    "def sample_and_save(model, device, sample_dir, epoch, n_samples=16, steps=100):\n",
    "    model.eval()\n",
    "    with torch.no_grad():\n",
    "        z = torch.randn(n_samples, 1, 28, 28, device=device)\n",
    "        x_t = z.clone()\n",
    "        dt = 1.0 / steps\n",
    "        # simple Euler integration from t=0 to t=1\n",
    "        for i in range(steps):\n",
    "            t = torch.full((n_samples,), fill_value=i / steps, device=device)\n",
    "            v = model(x_t, t)  # predict v(x_t, t)\n",
    "            x_t = x_t + v * dt\n",
    "\n",
    "        # x_t should approximate data distribution mapped at t=1\n",
    "        out = (x_t.clamp(-1, 1) + 1) / 2  # map back to [0,1] for saving\n",
    "        utils.save_image(out, os.path.join(sample_dir, f'samples_ep{epoch}.png'), nrow=4)\n",
    "    print(f\"Saved samples to {os.path.join(sample_dir, f'samples_ep{epoch}.png')}\")\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b99fe84",
   "metadata": {},
   "source": [
    "### Simple Model Testing with Sample Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "fdab8324",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using device: cuda\n",
      "Output shape: torch.Size([1, 1, 28, 28])\n",
      "Number of parameters in the model: 0.81 Million\n"
     ]
    }
   ],
   "source": [
    "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n",
    "print(\"Using device:\", device)\n",
    "model = UNetSimple(time_emb_dim=128).to(device)\n",
    "#print(model)\n",
    "data = torch.randn(1, 1, 28, 28).to(device)\n",
    "output = model(data, torch.tensor([0.5], device=device))\n",
    "print(\"Output shape:\", output.shape)\n",
    "# number of parameters\n",
    "num_params = sum(p.numel() for p in model.parameters())\n",
    "# in Millions\n",
    "print(f\"Number of parameters in the model: {num_params / 1e6:.2f} Million\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46bba55b",
   "metadata": {},
   "source": [
    "### Training Flow Matching Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "2ba2c253",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1 Step 200/600 Loss: 0.500651\n",
      "Epoch 1 Step 400/600 Loss: 0.398728\n",
      "Epoch 1 Step 600/600 Loss: 0.355484\n",
      "=== Epoch 1 completed. Avg loss: 0.355484 ===\n",
      "Saved samples to samples/samples_ep1.png\n",
      "Epoch 2 Step 200/600 Loss: 0.250375\n",
      "Epoch 2 Step 400/600 Loss: 0.245938\n",
      "Epoch 2 Step 600/600 Loss: 0.243141\n",
      "=== Epoch 2 completed. Avg loss: 0.243141 ===\n",
      "Saved samples to samples/samples_ep2.png\n",
      "Epoch 3 Step 200/600 Loss: 0.231773\n",
      "Epoch 3 Step 400/600 Loss: 0.228119\n",
      "Epoch 3 Step 600/600 Loss: 0.225348\n",
      "=== Epoch 3 completed. Avg loss: 0.225348 ===\n",
      "Saved samples to samples/samples_ep3.png\n",
      "Epoch 4 Step 200/600 Loss: 0.218838\n",
      "Epoch 4 Step 400/600 Loss: 0.216983\n",
      "Epoch 4 Step 600/600 Loss: 0.216657\n",
      "=== Epoch 4 completed. Avg loss: 0.216657 ===\n",
      "Saved samples to samples/samples_ep4.png\n",
      "Epoch 5 Step 200/600 Loss: 0.211759\n",
      "Epoch 5 Step 400/600 Loss: 0.211713\n",
      "Epoch 5 Step 600/600 Loss: 0.211206\n",
      "=== Epoch 5 completed. Avg loss: 0.211206 ===\n",
      "Saved samples to samples/samples_ep5.png\n",
      "Epoch 6 Step 200/600 Loss: 0.207903\n",
      "Epoch 6 Step 400/600 Loss: 0.208237\n",
      "Epoch 6 Step 600/600 Loss: 0.207477\n",
      "=== Epoch 6 completed. Avg loss: 0.207477 ===\n",
      "Saved samples to samples/samples_ep6.png\n",
      "Epoch 7 Step 200/600 Loss: 0.205400\n",
      "Epoch 7 Step 400/600 Loss: 0.204407\n",
      "Epoch 7 Step 600/600 Loss: 0.204768\n",
      "=== Epoch 7 completed. Avg loss: 0.204768 ===\n",
      "Saved samples to samples/samples_ep7.png\n",
      "Epoch 8 Step 200/600 Loss: 0.203701\n",
      "Epoch 8 Step 400/600 Loss: 0.203075\n",
      "Epoch 8 Step 600/600 Loss: 0.201910\n",
      "=== Epoch 8 completed. Avg loss: 0.201910 ===\n",
      "Saved samples to samples/samples_ep8.png\n",
      "Epoch 9 Step 200/600 Loss: 0.200539\n",
      "Epoch 9 Step 400/600 Loss: 0.199055\n",
      "Epoch 9 Step 600/600 Loss: 0.198991\n",
      "=== Epoch 9 completed. Avg loss: 0.198991 ===\n",
      "Saved samples to samples/samples_ep9.png\n",
      "Epoch 10 Step 200/600 Loss: 0.197603\n",
      "Epoch 10 Step 400/600 Loss: 0.197708\n",
      "Epoch 10 Step 600/600 Loss: 0.197893\n",
      "=== Epoch 10 completed. Avg loss: 0.197893 ===\n",
      "Saved samples to samples/samples_ep10.png\n"
     ]
    }
   ],
   "source": [
    "train_flowmatch(device='cuda' if torch.cuda.is_available() else 'cpu',\n",
    "            epochs=10,\n",
    "            batch_size=64,\n",
    "            lr=2e-4,\n",
    "            steps_per_epoch=600,   # speed control — set None to run full dataset\n",
    "            model_save_dir='models',\n",
    "            sample_dir='samples',\n",
    "            integration_steps=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69db6cf3",
   "metadata": {},
   "source": [
    "### Sample Predictions After Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "e032a977",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# display samples in notebook\n",
    "from IPython.display import Image, display\n",
    "display(Image(filename='samples/samples_ep10.png'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02efb8dd",
   "metadata": {},
   "source": [
    "### Sample Predicted Images after First Epoch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "26908053",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "display(Image(filename='samples/samples_ep1.png'))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
